package redemption

import (
	"context"
	"math/rand"
	"time"

	"sale-admin/config/mysql"
	"sale-admin/internal/app/web/service/common"
	"sale-admin/internal/app/web/service/coupon"
	"sale-admin/internal/dal"
	"sale-admin/internal/dao"
	"sale-admin/internal/models"

	"192.168.1.75/go-pkg/errorx"
	"192.168.1.75/go-pkg/helper"
	"github.com/golang-module/carbon"
	"github.com/samber/lo"
	"gorm.io/gorm"
)

type RedemptionService struct{}

func RandomCode() (RandomCode string) {
	bytes := []byte{}
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	seed := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
	for i := 0; i < 8; i++ {
		bytes = append(bytes, seed[r.Intn(36)])
	}
	return string(bytes)
}

func GetUniqueRedemption(db *gorm.DB, shopID string) (code string) {
	for {
		code := RandomCode()
		var count int64
		db.Model(&models.MaRedemptionCode{}).
			Where("merchant_id = ?", shopID).
			Where("redemption_code = ?", code).
			Count(&count)
		if count == 0 {
			return code
		}
		continue
	}
}

// 新增兑换码
func (rs RedemptionService) Add(
	ctx context.Context,
	db *gorm.DB,
	merchantID string,
	addNum int,
	value float64,
	expirationTime,
	BrandName string,
) (CodeList []string, err error) {
	if addNum == 0 || value == 0 || expirationTime == "" {
		err = errorx.New("新建兑换码参数缺失", -1)
		return
	}
	if addNum > 200 {
		err = errorx.New("新建兑换码数量不能大于200张", -1)
		return
	}
	if value < 0 {
		err = errorx.New("兑换码价值不能小于0", -1)
	}
	BatchID, _ := helper.UUID{}.String()
	var batchInsertData []models.MaRedemptionCode
	for i := 0; i < addNum; i++ {
		var item models.MaRedemptionCode
		item.ID = merchantID
		item.MerchantID = merchantID
		item.BatchID = BatchID
		item.RedemptionCode = GetUniqueRedemption(db, merchantID)
		CodeList = append(CodeList, item.RedemptionCode)
		item.Value = value
		item.AddTime = time.Now()
		item.ExpirationTime = carbon.Parse(expirationTime).ToStdTime()
		item.NewExpirationTime = carbon.Parse(expirationTime).ToStdTime().Unix()
		item.RedemptionState = 1
		item.BrandName = BrandName
		batchInsertData = append(batchInsertData, item)
	}
	db.Model(&models.MaRedemptionCode{}).Create(&batchInsertData)

	// 添加日志
	var LogData models.MaRedemptionLog
	LogData.ID = merchantID
	LogData.MerchantID = merchantID
	LogData.BatchID = BatchID
	LogData.Value = value
	LogData.AddTime = time.Now()
	LogData.ExpirationTime = carbon.Parse(expirationTime).ToStdTime()
	LogData.NewExpirationTime = carbon.Parse(expirationTime).ToStdTime().Unix()
	LogData.Num = addNum
	db.Model(&models.MaRedemptionLog{}).Create(&LogData)
	return
}

// Remove  删除兑换码
func (rs RedemptionService) Remove(ctx context.Context, db *gorm.DB, ShopID, RedemptionCode string) (err error) {
	count := db.Model(&models.MaRedemptionCode{}).
		Where("merchant_id = ?", ShopID).
		UpdateColumn("redemption_code", RedemptionCode).RowsAffected
	if count <= 0 {
		return errorx.New("删除失败", -1)
	}
	return
}

// Status 兑换码状态
func (rs RedemptionService) Status(ctx context.Context, db *gorm.DB, merchantID, redemption_code string) (status int, err error) {
	// 先查询旧的兑换码，如果不存在，再查询新的兑换码
	var redemptionCode models.MaRedemptionCode
	found := db.Model(&models.MaRedemptionCode{}).
		Where("redemption_code = ?", redemption_code).
		Where("merchant_id = ?", merchantID).
		Take(&redemptionCode).
		RowsAffected
	if found == 1 {
		return redemptionCode.RedemptionState, nil
	}
	// 查询新的优惠码-兑换码
	status, err = dao.CouponCode{}.Status(ctx, dal.Q, merchantID, redemption_code)
	if err != nil {
		return status, err
	}
	return status, nil
}

type UsageLogRecord struct {
	UsedAt    int64  `json:"used_at" gorm:"column:used_at"`
	GoodsID   string `json:"goods_id" gorm:"column:goods_id"`
	GoodsName string `json:"goods_name" gorm:"column:goods_name"`
}

// UseRecords 兑换码使用记录
func (rs RedemptionService) UsageLog(
	ctx context.Context,
	db *gorm.DB,
	merchantID,
	redemption_code string,
	startTime,
	endTime,
	page,
	limit int,
) ([]UsageLogRecord, error) {
	var usageLogRecord []UsageLogRecord
	// 兑换码表
	tx := db.Table("? as r", models.MaRedemptionCode{}.TableName())
	// 左联订单表
	tx.Joins("LEFT JOIN ? o ON r.out_trade_no = o.out_trade_no", models.MaOrder{}.TableName())
	// 查询的字段
	tx.Select(
		"r.new_usage_time as used_at",
		"JSON_UNQUOTE(JSON_EXTRACT(o.count_data,'$[0].GoodsID')) as goods_id",
		"JSON_UNQUOTE(JSON_EXTRACT(o.count_data,'$[0].GoodsName')) as goods_name",
	)
	// 商户过滤
	tx.Where("r.merchant_id = ?", merchantID)
	// 开始时间
	if startTime > 0 {
		tx.Where("r.new_usage_time > ?", startTime)
	}
	// 结束时间
	if endTime > 0 {
		tx.Where("r.new_usage_time < ?", endTime)
	}
	// 兑换码过滤
	if redemption_code != "" {
		tx.Where("r.redemption_code = ?", redemption_code)
	}
	// 已使用
	{
		tx.Where(
			db.Where("r.new_usage_time IS NOT NULL").Or("r.new_usage_time > 0"),
		)
	}
	// 按使用时间降序
	tx.Order("r.new_usage_time desc")
	// 分页查询
	helper.Gorm{}.Paginate(tx, page, limit).Find(&usageLogRecord)
	return usageLogRecord, nil
}

type RCRes struct {
	models.MaRedemptionCode
	GoodsName string `gorm:"-" json:"goods_name"`
}

func (rs RedemptionService) GetRC(ctx context.Context, db *gorm.DB, merchantID string, shopIDList []string, page, limit int,
	RedemptionCode string, RedemptionState *int, BatchID string,
) (Res []RCRes, count int64, err error) {
	tx := db.Model(&models.MaRedemptionCode{})
	// 当不为管理员时，只能看到自己及子商户的
	if merchantID != "1" {
		merchantIDs, err1 := common.Order{}.GetMerchantChildren(ctx, merchantID, shopIDList)
		if err1 != nil {
			err = err1
			return
		}
		tx.Where("merchant_id in (?)", merchantIDs)
	}

	if RedemptionCode != "" {
		tx.Where("redemption_code like (?)", "%"+RedemptionCode+"%")
	}
	if RedemptionState != nil {
		if *RedemptionState != 0 && *RedemptionState != 1 && *RedemptionState != 2 {
			err = errorx.New("使用状态错误", -1)
			return
		}
		tx.Where("redemption_state = ?", *RedemptionState)
	}
	if BatchID != "" {
		tx.Where("batch_id = ?", BatchID)
	}
	tx.Count(&count)
	Res = []RCRes{}
	helper.Gorm{}.Paginate(tx, page, limit).Order("add_time desc").Find(&Res)
	var GoodsIDList []string
	for _, v := range Res {
		if v.GoodsID != "" && v.GoodsID != "0" {
			GoodsIDList = append(GoodsIDList, v.GoodsID)
		}
	}
	GoodsList := []struct {
		GoodsID   string `json:"goods_id"`
		GoodsName string `json:"goods_name1"`
	}{}
	db.Model(&models.MaGoodsInfo{}).Where("goods_id in (?)", GoodsIDList).Select("goods_id,goods_name1").Find(&GoodsList)
	GoodsIDNameMap := make(map[string]string)
	for _, v := range GoodsList {
		GoodsIDNameMap[v.GoodsID] = v.GoodsName
	}
	for k, v := range Res {
		if _, ok := GoodsIDNameMap[v.GoodsID]; ok {
			Res[k].GoodsName = GoodsIDNameMap[v.GoodsID]
		}
	}
	return
}

func (rs RedemptionService) GetLog(ctx context.Context, db *gorm.DB, merchantID string, shopIDList []string, page, limit int) (Res []models.MaRedemptionLog, count int64, err error) {
	tx := db.Model(&models.MaRedemptionLog{})
	merchantIDs, err1 := common.Order{}.GetMerchantChildren(ctx, merchantID, shopIDList)
	if err1 != nil {
		err = err1
		return
	}
	tx.Where("merchant_id in (?)", merchantIDs)
	tx.Count(&count)

	Res = []models.MaRedemptionLog{}
	helper.Gorm{}.Paginate(tx, page, limit).Order("add_time desc").Find(&Res)
	return
}

// QueryRCOrder 兑换码订单查询
func (rs RedemptionService) QueryRCOrder(ctx context.Context, salesID, outTradeNo, code string) (data interface{}, err error) {
	db := mysql.NewDB()
	// 判断设备是否存在
	robotDetail, _ := dao.Robot{}.Detail(ctx, dal.Q, "", salesID)
	if robotDetail == nil {
		return nil, errorx.New("设备不存在", -1)
	}
	// 判断订单是否存在
	var OrderInfo models.MaOrder
	db.Model(&models.MaOrder{}).
		Where("out_trade_no = ?", outTradeNo).
		Take(&OrderInfo)
	if OrderInfo.MerchantID == "" {
		err = errorx.New("订单信息不存在", -1)
		return
	}
	// 查询码信息
	// 先查询原有的兑换码
	// 不存在再查询新的兑换码，过度一段时候
	var CodeInfo models.MaRedemptionCode
	found := db.Model(&models.MaRedemptionCode{}).
		Where("redemption_code = ?", code).
		Take(&CodeInfo).
		RowsAffected
	if found == 1 {
		// 检查兑换码是否已使用
		var found int64
		db.Model(&models.MaRedemptionCode{}).
			Where("out_trade_no = ?", outTradeNo).
			Count(&found)
		if found > 0 {
			err = errorx.New("兑换码已使用", -1)
			return
		}
		// 验证兑换码状态
		if CodeInfo.RedemptionCode == "" {
			err = errorx.New("兑换码不匹配", 2)
			return
		} else if CodeInfo.Value < OrderInfo.PaymentAmount {
			err = errorx.New("兑换码金额不匹配", 4)
			return
		} else if CodeInfo.RedemptionState == 0 {
			err = errorx.New("兑换码已过期", -1)
			return
		} else if CodeInfo.RedemptionState == 2 {
			err = errorx.New("兑换码已使用", 6)
			return
		} else {
			// 更新兑换码状态
			db.Model(&models.MaRedemptionCode{}).
				Where("redemption_code", code).
				Updates(map[string]interface{}{
					"exchange_value":   OrderInfo.PaymentAmount,
					"sales_id":         salesID,
					"robot_name":       robotDetail.RobotName,
					"usage_time":       time.Now(),
					"out_trade_no":     outTradeNo,
					"redemption_state": 2, // 已使用
					"new_usage_time":   time.Now().Unix(),
				})
		}
	} else {
		_, goodsIDs, _, _, _, err := coupon.CouponCode{}.Check(ctx, salesID, 0, code, 2, 0)
		if err != nil {
			return nil, err
		}
		if !lo.Contains(goodsIDs, OrderInfo.GoodsID) {
			return nil, errorx.New("不适用该商品", -1)
		}
		// 核销锁定
		err = coupon.CouponCode{}.ConsumeLock(ctx, code, outTradeNo, time.Minute*5)
		if err != nil {
			return nil, err
		}
	}
	return
}
